#include "syscall.h"
#include "../proc/proc.h"
#include "../boot/console.h"
#include "../boot/uart.h"

#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR   2

static struct file console_file_ro;
static struct file console_file_wo;
static struct file console_file_rw;

static int
str_eq(const char *a, const char *b)
{
  while(*a && *b){
    if(*a != *b)
      return 0;
    a++;
    b++;
  }
  return *a == *b;
}

static int
fdalloc(struct proc *p, struct file *f)
{
  for(int fd = 0; fd < NOFILE; fd++){
    if(p->ofile[fd] == 0){
      p->ofile[fd] = f;
      return fd;
    }
  }
  return -1;
}

static int
file_mode(struct file *f)
{
  if(f == &console_file_ro)
    return O_RDONLY;
  if(f == &console_file_wo)
    return O_WRONLY;
  if(f == &console_file_rw)
    return O_RDWR;
  return -1;
}

static int
is_console_read_fd(struct proc *p, int fd)
{
  if(fd < 0 || fd >= NOFILE)
    return 0;
  struct file *f = p->ofile[fd];
  if(f == 0)
    return fd == 0; // default stdin
  int mode = file_mode(f);
  return mode == O_RDONLY || mode == O_RDWR;
}

static int
is_console_write_fd(struct proc *p, int fd)
{
  if(fd < 0 || fd >= NOFILE)
    return 0;
  struct file *f = p->ofile[fd];
  if(f == 0)
    return fd == 1 || fd == 2; // default stdout/stderr
  int mode = file_mode(f);
  return mode == O_WRONLY || mode == O_RDWR;
}

// 系统调用：exec - 执行新程序（暂未实现）
uint64
sys_exec(void)
{
  // 暂未实现
  return -1;
}

// 系统调用：open - 打开文件（暂未实现）
uint64
sys_open(void)
{
  char path[128];
  int omode;
  struct proc *p = myproc();

  if(argstr(0, path, sizeof(path)) < 0)
    return -1;
  argint(1, &omode);

  struct file *target = 0;
  if(str_eq(path, "console")){
    if(omode == O_RDONLY)
      target = &console_file_ro;
    else if(omode == O_WRONLY)
      target = &console_file_wo;
    else if(omode == O_RDWR)
      target = &console_file_rw;
    else
      target = &console_file_wo;
  } else {
    return -1;
  }

  int fd = fdalloc(p, target);
  if(fd < 0)
    return -1;
  return fd;
}

// 系统调用：read - 读取文件
uint64
sys_read(void)
{
  int fd;
  uint64 dst;
  int n;
  struct proc *p = myproc();

  argint(0, &fd);
  argaddr(1, &dst);
  argint(2, &n);

  if(n < 0)
    return -1;
  if(n == 0)
    return 0;

  if(!is_console_read_fd(p, fd))
    return -1;

  int copied = 0;
  int chunk_len = 0;
  char buf[64];

  while(copied < n){
    char c = (char)uart_getc();
    if(c == '\r')
      c = '\n';
    buf[chunk_len++] = c;
    copied++;

    if(chunk_len == sizeof(buf) || c == '\n' || copied == n){
      if(copyout(p->pagetable, dst + copied - chunk_len, buf, chunk_len) < 0)
        return -1;
      chunk_len = 0;
      if(c == '\n')
        break;
    }
  }

  return copied;
}

// 系统调用：write 
uint64
sys_write(void)
{
  int fd;
  uint64 src;
  int n;
  struct proc *p = myproc();

  argint(0, &fd);
  argaddr(1, &src);
  argint(2, &n);

  if(n < 0)
    return -1;

  if(!is_console_write_fd(p, fd))
    return -1;

  int total = 0;
  char buf[128];

  while(total < n){
    int m = n - total;
    if(m > (int)sizeof(buf))
      m = sizeof(buf);
    if(copyin(p->pagetable, buf, src + total, m) < 0)
      return -1;
    for(int i = 0; i < m; i++){
      console_putc(buf[i]);
    }
    total += m;
  }
  return total;
}

// 系统调用：close 
uint64
sys_close(void)
{
  int fd;
  struct proc *p = myproc();

  argint(0, &fd);
  if(fd < 0 || fd >= NOFILE)
    return -1;

  p->ofile[fd] = 0;
  return 0;
}

// 系统调用：fstat 
uint64
sys_fstat(void)
{
  // 暂未实现
  return -1;
}

// 系统调用：link 
uint64
sys_link(void)
{
  // 暂未实现
  return -1;
}

// 系统调用：unlink - 删除文件（暂未实现）
uint64
sys_unlink(void)
{
  // 暂未实现
  return -1;
}

// 系统调用：mkdir - 创建目录（暂未实现）
uint64
sys_mkdir(void)
{
  // 暂未实现
  return -1;
}

// 系统调用：mknod - 创建设备节点（暂未实现）
uint64
sys_mknod(void)
{
  // 暂未实现
  return -1;
}

// 系统调用：chdir - 改变工作目录（暂未实现）
uint64
sys_chdir(void)
{
  // 暂未实现
  return -1;
}

// 系统调用：dup - 复制文件描述符（暂未实现）
uint64
sys_dup(void)
{
  // 暂未实现
  return -1;
}

// 系统调用：pipe - 创建管道（暂未实现）
uint64
sys_pipe(void)
{
  // 暂未实现
  return -1;
}

